from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, PickleType
from sqlalchemy.orm import sessionmaker, relationship,declarative_base
import os
import re
import json
import sys

from socketio import Client

import multiprocessing

sio3 = Client()
    # 发送消息给服务器
def send_message_to_server3(message):
    sio3.emit('generate_data_message', {'message': message}, namespace='/generate_data')

def send_data_to_server3(message):
    sio3.emit('generate_Jsondata_message', {'message': message}, namespace='/generate_data')
    
def run_client3():
    # 运行客户端
    sio3.wait()


# print("数据库创建")
engine = create_engine('sqlite:///temp/solar_structure.db')
max_line=10
# 创建模型基类
Base = declarative_base()

import datetime
# 定义树节点模型

# coding:utf-8
import nltk
import jieba
import numpy

# #对停用词加载
# def stopwordslist(filepath):
#     stopwords = [line.strip() for line in open('停用词.txt', 'r', encoding='utf-8').readlines()]
#     return stopwords

#对句子打分
def score_sentences(sentences,topn_words):#参数 sentences：文本组（分好句的文本，topn_words：高频词组
    scores=[]
    sentence_idx=-1#初始句子索引标号-1
    for s in [list(jieba.cut(s)) for s in sentences]:# 遍历每一个分句，这里的每个分句是 分词数组 分句1类似 ['花', '果园', '中央商务区', 'F4', '栋楼', 'B33', '城', '，']
        sentence_idx+=1 #句子索引+1。。0表示第一个句子
        word_idx=[]#存放关键词在分句中的索引位置.得到结果类似：[1, 2, 3, 4, 5]，[0, 1]，[0, 1, 2, 4, 5, 7]..
        for w in topn_words:#遍历每一个高频词
            try:
                word_idx.append(s.index(w))#关键词出现在该分句子中的索引位置
            except ValueError:#w不在句子中
                pass
        word_idx.sort()
        if len(word_idx)==0:
            continue

        #对于两个连续的单词，利用单词位置索引，通过距离阀值计算族
        clusters=[] #存放的是几个cluster。类似[[0, 1, 2], [4, 5], [7]]
        cluster=[word_idx[0]] #存放的是一个类别（簇） 类似[0, 1, 2]
        i=1
        while i<len(word_idx):#遍历 当前分句中的高频词
            CLUSTER_THRESHOLD=2#举例阈值我设为2
            if word_idx[i]-word_idx[i-1]<CLUSTER_THRESHOLD:#如果当前高频词索引 与前一个高频词索引相差小于3，
                cluster.append(word_idx[i])#则认为是一类
            else:
                clusters.append(cluster[:])#将当前类别添加进clusters=[]
                cluster=[word_idx[i]] #新的类别
            i+=1
        clusters.append(cluster)

        #对每个族打分，每个族类的最大分数是对句子的打分
        max_cluster_score=0
        for c in clusters:#遍历每一个簇
            significant_words_in_cluster=len(c)#当前簇 的高频词个数
            total_words_in_cluster=c[-1]-c[0]+1#当前簇里 最后一个高频词 与第一个的距离
            score=1.0*significant_words_in_cluster*significant_words_in_cluster/total_words_in_cluster
            if score>max_cluster_score:
                max_cluster_score=score
        scores.append((sentence_idx,max_cluster_score))#存放当前分句的最大簇（说明下，一个分解可能有几个簇） 存放格式（分句索引，分解最大簇得分）
    return scores
class TreeNode(Base):
    __tablename__ = 'tree_nodes'
    id = Column(String, primary_key=True)
    key_words = Column(String)
    parent_id = Column(String, ForeignKey('tree_nodes.id'))
    children_id = Column(PickleType)
    start_time= Column(String)
    end_time=Column(String)
    start_line=Column(Integer)
    end_line=Column(Integer)

# 创建数据库表
Base.metadata.create_all(engine)
# 创建会话
Session = sessionmaker(bind=engine)
session = Session()

def GetParentId(id_input):
    #如果输入的id是一级id，返回0
    if '.' not in id_input:
        return '0'
    # 要创建的新节点的 ID
    new_node_id = id_input

    # 解析 ID，分割成各级标识
    node_ids = new_node_id.split(".")

    # 找到父节点的 ID，通过去掉最后一个标识
    parent_node_id = ".".join(node_ids[:-1])
    return str(parent_node_id)

def AddNode(id_input, key_words_input):
    parent_id = GetParentId(id_input)

    # 查询父节点
    parent_node = session.query(TreeNode).filter(TreeNode.id == parent_id).first()

    if parent_node:
        new_node = TreeNode(id=id_input, key_words=key_words_input, parent_id=parent_id)
        # 将新节点添加到父节点的 children 列表中
        if parent_node.children_id is None:
            parent_node.children_id = []
        parent_node.children_id.append(id_input)
        session.add(new_node)
        session.commit()
    else:
        print(f"未找到ID为{parent_id}的父节点。")


def ShowTree(node_id, indent=0):
    # 查询当前节点
    node = session.query(TreeNode).filter(TreeNode.id == node_id).first()

    if not node:
        return

    # 打印节点的名称和关键词，带有缩进表示节点层次
    print("  " * indent + f"{node.id} - {node.key_words}   {node.start_time}   {node.end_time} {node.start_line} {node.end_line}")

    # 查询所有子节点
    children = session.query(TreeNode).filter(TreeNode.parent_id == node_id).all()

    # 递归打印子节点
    for child in children:
        ShowTree(child.id, indent + 1)

def InputFile(file_input):
    with open(file_input, 'r', encoding='utf-8') as f:
        for line in f:
            line = line.strip()
            if line:
                line = re.sub(r'^\s*', '', line)
                id_input, key_words_input = line.split(' ',1)
                if id_input.endswith('.'):
                    # 如果是，去除最后一个字符
                   id_input = id_input[:-1]
                AddNode(id_input, key_words_input)

def FindNodesAndKeywordsAtLevel(target_level, current_level=0,ifReturnid=1,node_id='0'):
    if current_level == target_level:
        # If the current level matches the target level, return this node's ID and key_words
        node = session.query(TreeNode).filter(TreeNode.id == node_id).first()
        if node:
            if ifReturnid:
                return [(node_id, node.key_words,node.parent_id)]
            return [node.key_words]
        else:
            return []

    # Get all children of the current node
    children = session.query(TreeNode.id).filter(TreeNode.parent_id == node_id).all()

    # Recursively search for nodes and key_words at the target level
    result = []
    for child_id in children:
        child_id = child_id[0]  # Unpack the result
        result.extend(FindNodesAndKeywordsAtLevel(target_level, current_level=current_level + 1,node_id=child_id))

    return result

def GetTreeDepth(node_id='0', current_depth=0):
    # 查询当前节点
    node = session.query(TreeNode).filter(TreeNode.id == node_id).first()

    # 查询所有子节点
    children = session.query(TreeNode.id).filter(TreeNode.parent_id == node_id).all()

    # 如果没有子节点，直接返回当前深度
    if not children:
        return current_depth

    # 递归计算子节点的深度
    child_depths = []
    for child_id in children:
        child_id = child_id[0]
        child_depths.append(GetTreeDepth(child_id, current_depth + 1))

    # 返回子节点深度的最大值
    return max(child_depths)

def GetLowestLevelWithoutRepetion(root_id='0'):
    tree_depth=GetTreeDepth('0')
    lowest_level_without_repetion=tree_depth
    level=FindNodesAndKeywordsAtLevel(lowest_level_without_repetion,ifReturnid=0)
    level_keywords=[]
    for i in level:
        level_keywords.append(i)
    while True:
        if len(level_keywords)==len(set(level_keywords)) or lowest_level_without_repetion==0:
            break
        lowest_level_without_repetion-=1
    return lowest_level_without_repetion

def GetTime(level,source_file,lowest_level_without_repetion,root_id='0'):
    
    with open(source_file,'r',encoding='utf-8') as file:
        content=file.readlines()

    nodes_infor=FindNodesAndKeywordsAtLevel(level)
    if level>=lowest_level_without_repetion:#检测是否位于最低非重复层
        for node_infor in nodes_infor:
            parent=session.query(TreeNode).filter(TreeNode.id == node_infor[2]).first()
            start_line=0
            end_line=max_line
            if parent is not None:
                start_line=parent.start_line
                end_line=parent.end_line
            if level==lowest_level_without_repetion or (parent is None) or (start_line is None) or (end_line is None):
                start_line=0
                end_line=max_line
            #初始化查找
            node_id=node_infor[0]
            node=session.query(TreeNode).filter(TreeNode.id == node_id).first()
            search_string=node_infor[1]
            first_occurrence_line=0
            last_occurrence_line=max_line
            occurrence_count=0
            #print(node_infor[1],start_line,end_line)
            # 遍历每一行并查找字符串
            for line_number, line in enumerate(content, start=1):
                if line_number>=start_line and line_number<=end_line:
                    text=jieba.lcut(search_string)
                    lines=[]
                    lines.append(line)
                    # print(lines,text)
                    score=score_sentences(lines,text)
                    if len(score)!=0: 
                        # print(score)
                        score=score[0][1]
                    else: score=0
                    if score >=2.0:
                        occurrence_count += 1
                        if first_occurrence_line == 0:
                            first_occurrence_line = line_number
                        last_occurrence_line = line_number
            print(search_string,first_occurrence_line,last_occurrence_line)
            if last_occurrence_line==max_line:
                last_occurrence_line=start_line
            line_to_get=content[first_occurrence_line]
            #print(line_to_get)
            # 使用正则表达式匹配 "bg:" 后面的数字
            bg_match = re.search(r'start:\s*([0-9.]+)', line_to_get)
            #print(re.search(r'start:\s*([0-9.]+)', line_to_get))
            line_to_get=content[last_occurrence_line]
            # 使用正则表达式匹配 "ed:" 后面的数字
            ed_match = re.search(r'end:\s*([0-9.]+)', line_to_get)
            #print(re.search(r'end:\s*([0-9.]+)', line_to_get))
            if bg_match and ed_match:
                node.start_time = bg_match.group(1)
                node.end_time = ed_match.group(1)
                node.start_line=first_occurrence_line
                node.end_line=last_occurrence_line
            else :
                node.start_line=0
                node.end_line = max_line
    else:
        for node_infor in nodes_infor:
            #初始化查找
            node_id=node_infor[0]
            node=session.query(TreeNode).filter(TreeNode.id == node_id).first()
            if node.children_id is not None:
                children = session.query(TreeNode).filter(TreeNode.parent_id == node_id).all()
                print(children,"flag")
                start_time=children[0].start_time
                end_time=children[-1].end_time
                for child in children:
                    if float(start_time)>float(child.start_time):
                        start_time=child.start_time
                    if float(end_time)<float(child.end_time):
                        end_time=child.end_time
                node.start_time=start_time
                node.end_time=end_time
            else:
                start_line=0
                end_line=max_line
                #初始化查找
                node_id=node_infor[0]
                node=session.query(TreeNode).filter(TreeNode.id == node_id).first()
                search_string=node_infor[1]
                first_occurrence_line=0
                last_occurrence_line=0
                occurrence_count=0
                print(node_infor[1],start_line,end_line)
                # 遍历每一行并查找字符串
                for line_number, line in enumerate(content, start=1):
                    if line_number>=start_line and line_number<=end_line:
                        text=jieba.lcut(search_string)
                        lines=[]
                        lines.append(line)
                        # print(lines,text)
                        score=score_sentences(lines,text)
                        if len(score)!=0: 
                            # print(score)
                            score=score[0][1]
                        else: score=0
                        if score >=2.0:
                            occurrence_count += 1
                            if first_occurrence_line == 0:
                                first_occurrence_line = line_number
                            last_occurrence_line = line_number

                line_to_get=content[first_occurrence_line-1]
                # 使用正则表达式匹配 "bg:" 后面的数字
                bg_match = re.search(r'start:(\d+)', line_to_get)

                line_to_get=content[last_occurrence_line-1]
                # 使用正则表达式匹配 "ed:" 后面的数字
                ed_match = re.search(r'end:(\d+)', line_to_get)
                if bg_match and ed_match:
                    node.start_time = bg_match.group(1)
                    node.end_time = ed_match.group(1)
                node.start_line = 0
                node.end_line = max_line
            

def TreeToDict(node_id='0'):
    node = session.query(TreeNode).filter(TreeNode.id == node_id).first()
    if not node:
        return {}

    # 创建节点字典
    node_dict = {
        "id": '1.'+node.id,
        "key_words": node.key_words,
        "start_time": node.start_time,
        "end_time": node.end_time,
        "children": []
    }
    if node.id=='0':
        node_dict['id']='1'
    # 查询所有子节点
    children = session.query(TreeNode).filter(TreeNode.parent_id == node_id).all()

    # 递归调用以获取子节点的字典
    for child in children:
        child_dict = TreeToDict(child.id)
        if child_dict:
            node_dict["children"].append(child_dict)

    return node_dict

def GetTreeJson(extract_path,
                time_path,
                json_path):
    
    time_dir=r"temp\time.txt"
    # 检查根节点是否存在，如果不存在则创建它
    root_node = session.query(TreeNode).filter(TreeNode.id == '0').first()
    if not root_node:
        # 如果根节点不存在，插入它
        root_node = TreeNode(id='0', key_words='Root Node', parent_id=None)
        session.add(root_node)
        session.commit()
    InputFile(extract_path)
    send_message_to_server3(90)
    tree_depth=GetTreeDepth()
    lowest_level_without_repetion=GetLowestLevelWithoutRepetion()
    
    #lowest_level_without_repetion=1
    for i in range(lowest_level_without_repetion,tree_depth+1):
        GetTime(i,time_path,lowest_level_without_repetion)
    for i in range(lowest_level_without_repetion-1,-1,-1):
        GetTime(i,time_path,lowest_level_without_repetion)
    ShowTree('0')
    # 将根节点转换为字典
    tree_dict = TreeToDict('0')
    send_message_to_server3(95)
    send_data_to_server3(tree_dict)
    # json_id=datetime.datetime.now().strftime("%Y%m%d%H%M%S")
    # with open(str(json_path)+str(json_id)+".json", 'w',encoding='utf-8') as json_file:
    # 将字典写入JSON文件
    with open(json_path, 'w',encoding='utf-8') as json_file:
        json.dump(tree_dict, json_file, indent=4,ensure_ascii=False)
        # os.remove(r"temp\solar_structure.db")
    return

if __name__ =="__main__":
    
    # 与app.py线程通信
    # 连接到服务器，并指定命名空间为 '/transformer'
    sio3.connect('http://127.0.0.1:8090', namespaces=['/generate_data'])


    # 创建并启动新进程
    client_process = multiprocessing.Process(target=run_client3)
    client_process.start()


    
    # 解析参数
    params = {}
    for i in range(1, len(sys.argv), 2):
        params[sys.argv[i]] = sys.argv[i+1]
  
    GetTreeJson(params['--param1'], params['--param2'], params['--param3'])
# GetTreeJson()
# tree_depth=GetTreeDepth()
# print(tree_depth,GetLowestLevelWithoutRepetion())